//==========================================================================
// Copyright (c) 2000-2008,  Elastos, Inc.  All Rights Reserved.
//==========================================================================
#include <core.h>
#include <_hal.h>

#ifdef _ELADBGAGENT

#include <slip.h>

#define SLIP_END            (unsigned char)192  /* indicates end of packet */
#define SLIP_ESC            (unsigned char)219  /* indicates byte stuffing */
/* SLIP_ESC SLIP_ESC_END means SLIP_END data byte */
#define SLIP_ESC_END        (unsigned char)220
/* SLIP_ESC SLIP_ESC_ESC means SLIP_ESC data byte */
#define SLIP_ESC_ESC        (unsigned char)221

#define SLIP_RECV_SUCCESS       0
#define SLIP_RECV_NODATA        1
#define SLIP_RECV_ERROR         2

static void send_char(unsigned char c);
static int recv_char(unsigned char *p);

static int slip_send_packet(unsigned char *p, int len);
static int slip_recv_packet(unsigned char *p, int len);

static __inline void send_char(unsigned char c)
{
    BspWriteComPort(COMPORT_DEBUG, c);
}

static __inline int recv_char(unsigned char *p)
{
    if (BspReadComPort(COMPORT_DEBUG, p))
        return SLIP_RECV_SUCCESS;
    else
        return SLIP_RECV_ERROR;
}

/////////////////////////////////////////////////////////////////////
/* slip_send_packet: sends a packet of length "len", starting at
 *                   location "p".
 */
static int slip_send_packet(unsigned char *p, int len)
{
    /* send an initial END character to flush out any data that may
     * have accumulated in the receiver due to line noise
     */

    send_char(SLIP_END);
    while (len--) {
        switch (*p) {
            /* if it's the same code as an END character, we send a
             * special two character code so as not to make the
             * receiver think we sent an END
             */
            case SLIP_END:
                send_char(SLIP_ESC);
                send_char(SLIP_ESC_END);
                break;

            /* if it's the same code as an ESC character,
             * we send a special two character code so as not
             * to make the receiver think we sent an ESC
             */
            case SLIP_ESC:
                send_char(SLIP_ESC);
                send_char(SLIP_ESC_ESC);
                break;

            /* otherwise, we just send the character
             */
            default:
                send_char(*p);
        }

        p++;
    }

    /* tell the receiver that we're done sending the packet
     */
    send_char(SLIP_END);
    return 0;
}

/* slip_recv_packet: receives a packet into the buffer located at "p".
 *                   If more than len bytes are received, the packet will
 *                   be truncated.
 *                   Returns the number of bytes stored in the buffer.
 */
static int slip_recv_packet(unsigned char *p, int len)
{
    unsigned char c;
    int received = 0;

    while (1) {
        if (recv_char(&c) == SLIP_RECV_SUCCESS) {
            switch (c) {

                /* if it's an END character then we're done with
                 * the packet
                 */
                case SLIP_END:
                    if (received)
                        return received;
                    else
                        break;

                /* if it's the same code as an ESC character, wait
                 * and get another character and then figure out
                 * what to store in the packet based on that.
                 */
                case SLIP_ESC:
                    if (recv_char(&c) == SLIP_RECV_SUCCESS) {
                        /* if "c" is not one of these two, then we
                         * have a protocol violation.  The best bet
                         * seems to be to leave the byte alone and
                         * just stuff it into the packet
                         */
                        switch (c) {
                            case SLIP_ESC_END:
                                c = (unsigned char)SLIP_END;
                                break;
                            case SLIP_ESC_ESC:
                                c = (unsigned char)SLIP_ESC;
                                break;
                        }
                    }
                    else
                        return 0;
                default:
                    if (received < len)
                        p[received++] = c;
            }
        }
        else
            return 0;
    }
}

Boolean CreateServerTransport(wchar_t * szName, UInt32 nClient)
{
    /* Machine-dependent code calls DbgPortInit
     * very early during initialization.
     */
    return TRUE;
}

Boolean ListenToTransport(void)
{
    Boolean ret = FALSE;
    int dbgret;
    char resetdbg[] = "Reset win32 debugger.";

    /* Waiting for a client.  Return FALSE if timed-out.
     * Otherwise, ACK (with another RESET message) to the
     * client and return TRUE.  The remote conterpart of
     * this algorithm is the loop in CreateClientTransport().
     */
    kprintf("ListenToTransport: enter...\n");

    dbgret = slip_recv_packet((UInt8 *)resetdbg, sizeof(resetdbg));
    if (dbgret > 0) {
        kprintf("received a packer.\n");
        //"Reset win32 debugger.";
        slip_send_packet((UInt8 *)resetdbg, dbgret);
        kprintf("sent a packet.\n");
        ret = TRUE;
    }

    return ret;
}

Boolean HangupTransport(void)
{
    return TRUE;
}

UInt32 WriteTransport(PTR pBuf, UInt32 BufSize)
{
    if ((Int32)BufSize < 0) {
        /*Packet.PacketType   = (UInt16)XP_TYPE_DATA_NO_ACK;*/
        BufSize = (UInt32)(-(Int32)BufSize);
    }

    slip_send_packet((UInt8 *)pBuf, BufSize);

    return BufSize;
}

UInt32 ReadTransport(PTR pBuf, UInt32 BufSize)
{
    Int32 ret;

    /* Must have preemption disabled in this code,
     * or we will never be able to handle the serial IO
     * in a timely fashion - we would be vulnerable to overruns.
     */

    if ((Int32)BufSize < 0) {
        /*PacketType = XP_TYPE_DATA_NO_ACK;*/
        BufSize = (UInt32)(-(Int32)BufSize);
    }

    do {
        ret = slip_recv_packet((UInt8 *)pBuf, BufSize);
    } while (ret <= 0);

    return ret;
}

#endif //_ELADBGAGENT
